#include "StdAfx.h"

#include <memory>
#include <QxtCore/QxtLogger>
#include "../VCommon/vmodule.h"
#include "../VSettings/vsettings.h"
#include "../scriptEngine/vblank.h"
#include "../scriptEngine/vblanktexteditor.h"
#include "../scriptEngine/vblankview.h"
#include "../scriptEngine/vqmlcompiler.h"

#include "vblankeditorview.h"

namespace
{
	const QString SRIPT_EXPLORER_TITLE = QObject::tr("Demo scripts");
	const QString CUR_SCRIPT_MARKER = QObject::tr("<---");
	const QString DEF_SCRIPT_NAME = "script";
	const QString CUR_SCRIPT_ICON = ":/Resources/Icons_se/checkscript.png";
	const QString rsrcPath = ":/Resources/Icons_se";
}

//////////////////////////////////////////////////////////////////////////
// VTabManager
VTabManager::VTabManager( QObject* parent)
{
}

VTabManager::~VTabManager()
{
}

QWidget* VTabManager::addTab(QWidget* parent, const QString& fileName, TabType type)
{
	QString scriptFullNameL(fileName.toLower());

	ScriptDescription sd;
	sd.fullPath = scriptFullNameL;

	switch (type)
	{
	case Editor:
		{
			if (m_editors.count() == 1)
				removeTab(m_editors.begin().key()->widget(), Editor);
			//else
			{
				VBlankTextEditor* be = new VBlankTextEditor(parent);		
				m_editors[be] = sd;
				return be->widget();
			}
		}		
	case View:
		{
			if (m_views.count() == 1)
				removeTab(m_views.begin().key()->widget(), View);
			//else
			{
				VBlankWidgetView* bv = new VBlankWidgetView(false, parent);		
				m_views[bv] = sd;
				return bv->widget();
			}
		}
	}
	return 0;
}

void VTabManager::removeTab(const QWidget* tabWidget, TabType type)
{
	switch(type)
	{
	case Editor:
		{
			QMap<VBlankTextEditor*, ScriptDescription>::iterator it = m_editors.begin();

			while ( it != m_editors.end())
			{
				if (it.key()->widget() == tabWidget)
				{
					delete it.key();
					m_editors.erase(it);
					break;
				}

				++it;
			}
		}
		break;

	case View:
		{
			QMap<VBlankWidgetView*, ScriptDescription>::iterator it = m_views.begin();

			while ( it != m_views.end())
			{
				if (it.key()->widget() == tabWidget)
				{
					delete it.key();
					m_views.erase(it);
					break;
				}

				++it;
			}
		}
		break;
	}
}

QWidget* VTabManager::findTab(const QString& fileName, TabType type) const
{
	if (type == View)
	{
		/*QMap<VBlankView*, ScriptDescription>::iterator it1 = m_views.begin();

		while ( it1 != m_views.end())
		{
			qDebug() << it1.value().fullPath << fileName.toLower();
			if (it1.value().fullPath == fileName.toLower())
				return it1.key()->widget();

			++it1;
		}*/
		return m_views.begin().key()->widget();
	}

	QMap<VBlankTextEditor*, ScriptDescription>::iterator it = m_editors.begin();

	while ( it != m_editors.end())
	{
		if (it.value().fullPath == fileName.toLower())
			return it.key()->widget();

		++it;
	}

	return 0;
}

VBlankTextEditor* VTabManager::editor(const QWidget* widget) const
{
	if (!widget)
		return m_editors.begin().key();

	QMap<VBlankTextEditor*, ScriptDescription>::iterator it = m_editors.begin();

	while ( it != m_editors.end())
	{
		if (it.key()->widget() == widget)
			return it.key();

		++it;
	}

	return 0;
}

VBlankWidgetView* VTabManager::view(const QWidget* widget) const
{
	QMap<VBlankWidgetView*, ScriptDescription>::iterator it = m_views.begin();

	while ( it != m_views.end())
	{
		if (it.key()->widget() == widget)
			return it.key();

		++it;
	}

	return 0;
}

int VTabManager::count(TabType type) const
{
	switch (type)
	{
	case Editor:
		return m_editors.count();
	case View:
		return m_views.count();
	}

	return 0;
}


//////////////////////////////////////////////////////////////////////////
// VBlankEditorTabWidget
int VBlankEditorTabWidget::addTab(QWidget* widget, const QString& caption, bool isClosable)
{
	int tabIdx = 0;
	
	if (!isClosable)
	{
		tabIdx = QTabWidget::addTab(widget, QIcon(":/Resources/Icons_se/filenew.png"), tr("Blank: %1").arg(caption));
		QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
		tabBar()->setTabButton(tabIdx, closeSide, 0);
	}
	else
		tabIdx = QTabWidget::addTab(widget, caption);

	return tabIdx;
}

/*void VBlankEditorTabWidget::event(QEvent* event)
{
	if (event->type() == QEvent::KeyRelease)
		return true, qDebug() << "key release";

	return false;
}*/

//////////////////////////////////////////////////////////////////////////
// VBlankEditorTreeWidget
void VBlankEditorTreeWidget::keyPressEvent(QKeyEvent *event)
{
	if (currentItem() == topLevelItem(currentColumn()))
	{
		QTreeWidget::keyPressEvent(event);
		return;
	}
	
	switch(event->key())
	{
	case Qt::Key_Enter:
	case Qt::Key_Return:
		emit enterKeyPressed(currentItem(), currentColumn());
		return;
	case Qt::Key_Delete:
		emit deleteKeyPressed(currentItem(), currentColumn());
		return;
	}

	QTreeWidget::keyPressEvent(event);
}

void VBlankEditorTreeWidget::mousePressEvent(QMouseEvent *event)
{
	m_canShowMenu = false;
	
	QPoint p(event->pos());
	QTreeWidgetItem* item = itemAt(p);
	QTreeWidgetItem* itemTop = topLevelItem(0);

	if (event->button()== Qt::RightButton && item != itemTop)
	{		
		setCurrentItem(item);
		if (item && !item->text(0).isEmpty())
			m_canShowMenu = true;
		
		return;
	}
	
	QTreeWidget::mousePressEvent(event);
}

void VBlankEditorTreeWidget::contextMenuEvent(QContextMenuEvent *event)
{
	if (!m_canShowMenu)
		return;

	QMenu *menu = new QMenu(this);
	foreach(QAction* a, m_actions)
		menu->addAction(a);

	menu->exec(QCursor::pos());
}

//////////////////////////////////////////////////////////////////////////
// VBlankEditorView
VBlankEditorView::VBlankEditorView(const QString& name)
	: VAbstractView(name)
	, m_treeSplitter(0)
	, m_tabSplitter(0)
	, m_curTreeItem(0)
	, m_curTabIdx(-1)
	, m_wasActivated(false)
	, m_newScriptCount(0)
	, m_copyScriptCount(1)
{
	QString scriptsDir;
	VSettings settings(QObject::metaObject()->className());
	scriptsDir = settings.value("scriptsDir", ".").toString();

	QDir curDir(scriptsDir);
	QStringList filters;
	filters << "*.qml";
	curDir.setNameFilters(filters);

	QRegExp newScriptRegExp("script(\\d+)\\.qml");
	QString files;	
	foreach (QString fileName, curDir.entryList(QDir::Files))
	{
		files.append(fileName);
	}

	QStringList list(files.split(newScriptRegExp));

	qDebug() << list;

	m_graphScene = new QGraphicsScene();
}

VBlankEditorView::~VBlankEditorView()
{
	VSettings settings(QObject::metaObject()->className());

	if (m_treeSplitter)
		settings.setValue("treeSplitter/State", m_treeSplitter->saveState());
	if (m_tabSplitter)
		settings.setValue("tabSplitter/State", m_tabSplitter->saveState());
}

void VBlankEditorView::activate()
{
	if (!m_wasActivated)
	{
		setupScriptActions();
		//setupTextActions();
		setupPrintActions();
		setupMainLayout();

		appendExistScripts();

		m_formatTbHelper = new VFormatToolbarHelper(this, this);
		m_toolbars.append(m_formatTbHelper->toolbar());
	}
}

void VBlankEditorView::deactivate()
{
	qDeleteAll(m_menus);
	m_menus.clear();
	
	qDeleteAll(m_toolbars);
	m_toolbars.clear();

	m_wasActivated = true;

	actionScriptSave();
}

QList<QMenu*> VBlankEditorView::menu() const
{
	return m_menus;
}

QList<QToolBar*> VBlankEditorView::toolbar() const
{
	return m_toolbars;
}

void VBlankEditorView::setupScriptActions()
{
	QToolBar* tb;
	tb = new QToolBar(tr("Script"), this);
	
	QAction* a;	
	a = new QAction(QIcon(":/Resources/Icons_se/filenew.png"), tr("New script"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptNew()));
	
	a = new QAction(QIcon(":/Resources/Icons_se/fileopen.png"), tr("Open script"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptOpen()));

	a = new QAction(QIcon(":/Resources/Icons_se/filesave.png"), tr("Save script"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptSave()));

	a = new QAction(QIcon(":/Resources/Icons_se/filesaveas.png"), tr("Save script as"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptSaveAs()));

	a = new QAction(QIcon(":/Resources/Icons_se/filecopy.png"), tr("Copy script"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptCopy()));

	a = new QAction(QIcon(":/Resources/Icons_se/filedelete.png"), tr("Delete script"), this);
	tb->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptDelete()));

	/*QAction* a = new QAction(QIcon(":/Resources/Icons_se/fileprint.png"), tr("&Print..."), this);
	a->setPriority(QAction::LowPriority);	
	connect(a, SIGNAL(triggered()), this, SLOT(scriptPrint()));
	m_tbScriptOp->addAction(a);
	
	a = new QAction(QIcon(":/Resources/Icons_se/fileprint.png"), tr("Print Preview..."), this);
	connect(a, SIGNAL(triggered()), this, SLOT(scriptPrintPreview()));
	m_tbScriptOp->addAction(a);*/

	m_toolbars.append(tb);	
}

void VBlankEditorView::setupTextActions()
{
	m_textActionToolbar = new QToolBar(this);//(qobject_cast<QWidget*>(textEdit->parent()));
	m_textActionToolbar->setWindowTitle(tr("Format Actions"));
	//tb->setWindowFlags(Qt::Tool | Qt::MSWindowsFixedSizeDialogHint /*| Qt::WindowTitleHint*/	| Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint);
	//tb->setFocusPolicy(Qt::NoFocus);

	actionTextBold = new QAction(QIcon::fromTheme("format-text-bold", QIcon(rsrcPath + "/textbold.png")),
		tr("&Bold"), this);
	actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B);
	actionTextBold->setPriority(QAction::LowPriority);
	QFont bold;
	bold.setBold(true);
	actionTextBold->setFont(bold);
	connect(actionTextBold, SIGNAL(triggered()), this, SLOT(textBold()));
	m_textActionToolbar->addAction(actionTextBold);		
	actionTextBold->setCheckable(true);

	actionTextItalic = new QAction(QIcon::fromTheme("format-text-italic", QIcon(rsrcPath + "/textitalic.png")),
		tr("&Italic"), this);
	actionTextItalic->setPriority(QAction::LowPriority);
	actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I);
	QFont italic;
	italic.setItalic(true);
	actionTextItalic->setFont(italic);
	connect(actionTextItalic, SIGNAL(triggered()), this, SLOT(textItalic()));
	m_textActionToolbar->addAction(actionTextItalic);
	actionTextItalic->setCheckable(true);

	actionTextUnderline = new QAction(QIcon::fromTheme("format-text-underline", QIcon(rsrcPath + "/textunder.png")),
		tr("&Underline"), this);
	actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U);
	actionTextUnderline->setPriority(QAction::LowPriority);
	QFont underline;
	underline.setUnderline(true);
	actionTextUnderline->setFont(underline);
	connect(actionTextUnderline, SIGNAL(triggered()), this, SLOT(textUnderline()));
	m_textActionToolbar->addAction(actionTextUnderline);
	actionTextUnderline->setCheckable(true);

	m_textActionToolbar->addSeparator();

	QActionGroup *grp = new QActionGroup(this);
	connect(grp, SIGNAL(triggered(QAction*)), this, SLOT(textAlign(QAction*)));

	// Make sure the alignLeft  is always left of the alignRight
	if (QApplication::isLeftToRight()) {
		actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")),
			tr("&Left"), grp);
		actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp);
		actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp);
	} else {
		actionAlignRight = new QAction(QIcon::fromTheme("format-justify-right", QIcon(rsrcPath + "/textright.png")), tr("&Right"), grp);
		actionAlignCenter = new QAction(QIcon::fromTheme("format-justify-center", QIcon(rsrcPath + "/textcenter.png")), tr("C&enter"), grp);
		actionAlignLeft = new QAction(QIcon::fromTheme("format-justify-left", QIcon(rsrcPath + "/textleft.png")), tr("&Left"), grp);
	}
	actionAlignJustify = new QAction(QIcon::fromTheme("format-justify-fill", QIcon(rsrcPath + "/textjustify.png")), tr("&Justify"), grp);

	actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
	actionAlignLeft->setCheckable(true);
	actionAlignLeft->setPriority(QAction::LowPriority);
	actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
	actionAlignCenter->setCheckable(true);
	actionAlignCenter->setPriority(QAction::LowPriority);
	actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
	actionAlignRight->setCheckable(true);
	actionAlignRight->setPriority(QAction::LowPriority);
	actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
	actionAlignJustify->setCheckable(true);
	actionAlignJustify->setPriority(QAction::LowPriority);

	m_textActionToolbar->addActions(grp->actions());
	m_textActionToolbar->addSeparator();

	QPixmap pix(16, 16);
	pix.fill(Qt::black);
	actionTextColor = new QAction(pix, tr("&Color..."), this);
	connect(actionTextColor, SIGNAL(triggered()), this, SLOT(textColor()));
	m_textActionToolbar->addAction(actionTextColor);

	m_textActionToolbar->addSeparator();

	comboStyle = new QComboBox(m_textActionToolbar);
	m_textActionToolbar->addWidget(comboStyle);
	comboStyle->addItem("Standard");
	comboStyle->addItem("Bullet List (Disc)");
	comboStyle->addItem("Bullet List (Circle)");
	comboStyle->addItem("Bullet List (Square)");
	comboStyle->addItem("Ordered List (Decimal)");
	comboStyle->addItem("Ordered List (Alpha lower)");
	comboStyle->addItem("Ordered List (Alpha upper)");
	comboStyle->addItem("Ordered List (Roman lower)");
	comboStyle->addItem("Ordered List (Roman upper)");
	connect(comboStyle, SIGNAL(activated(int)),
		this, SLOT(textStyle(int)));

	comboFont = new QFontComboBox(m_textActionToolbar);
	m_textActionToolbar->addWidget(comboFont);
	connect(comboFont, SIGNAL(activated(QString)),
		this, SLOT(textFamily(QString)));

	comboSize = new QComboBox(m_textActionToolbar);
	comboSize->setObjectName("comboSize");
	m_textActionToolbar->addWidget(comboSize);
	comboSize->setEditable(true);

	QFontDatabase db;
	foreach(int size, db.standardSizes())
		comboSize->addItem(QString::number(size));

	connect(comboSize, SIGNAL(activated(QString)),
		this, SLOT(textSize(QString)));
	comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font()
		.pointSize())));

	m_textActionToolbar->setEnabled(false);

	m_toolbars.append(m_textActionToolbar);
}

void VBlankEditorView::setupPrintActions()
{
	m_printerToolbar = new QToolBar(this);
	m_printerToolbar->setEnabled(false);

	QAction* a = new QAction(QIcon::fromTheme("document-print", QIcon(rsrcPath + "/fileprint.png")),
		tr("&Print..."), this);
	a->setPriority(QAction::LowPriority);    
	a->setShortcut(QKeySequence::Print);
	connect(a, SIGNAL(triggered()), this, SLOT(filePrint()));
	m_printerToolbar->addAction(a);

	a = new QAction(QIcon::fromTheme("fileprint", QIcon(rsrcPath + "/fileprint.png")),
		tr("Print Preview..."), this);
	connect(a, SIGNAL(triggered()), this, SLOT(filePrintPreview()));
	m_printerToolbar->addAction(a);
	
	m_toolbars.append(m_printerToolbar);
}

void VBlankEditorView::setupMainLayout()
{
	QHBoxLayout* l1 = new QHBoxLayout(this);
	
	m_treeSplitter = new QSplitter(this);
	l1->addWidget(m_treeSplitter);
		
	QDockWidget* dw1 = new QDockWidget(tr("Script explorer"), this);
	dw1->setFeatures(QDockWidget::NoDockWidgetFeatures);
	m_scriptExplorer = new VBlankEditorTreeWidget(this);
	m_scriptExplorer->setFocusPolicy(Qt::NoFocus);
	dw1->setWidget(m_scriptExplorer);

	QAction* a = new QAction(QIcon(":/Resources/Icons_se/filecopy.png"), tr("Copy script"), this);
	m_scriptExplorer->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptCopy()));

	a = new QAction(QIcon(":/Resources/Icons_se/filedelete.png"), tr("Delete script"), this);
	m_scriptExplorer->addAction(a);
	connect(a, SIGNAL(triggered()), this, SLOT(actionScriptDelete()));

	QTreeWidgetItem* topItem = new QTreeWidgetItem;
	topItem->setText(0, SRIPT_EXPLORER_TITLE);
	m_scriptExplorer->addTopLevelItem(topItem);

	m_tabSplitter = new QSplitter(Qt::Vertical, this);

	m_treeSplitter->addWidget(dw1);
	m_treeSplitter->addWidget(m_tabSplitter);	
	
	m_tabWidget = new VBlankEditorTabWidget(this);
	m_tabManager = new VTabManager(this);
	
	QDockWidget* dw2 = new QDockWidget(tr("Errors"), this);
	dw2->setFeatures(QDockWidget::NoDockWidgetFeatures);
	m_log = new QTextEdit(this);
	m_log->setReadOnly(true);

	dw2->setWidget(m_log);

	m_tabSplitter->addWidget(m_tabWidget);
	m_tabSplitter->addWidget(dw2);

	VSettings settings(QObject::metaObject()->className());
	
	m_tabSplitter->restoreState(
		settings.value("tabSplitter/State", m_tabSplitter->saveState()).toByteArray());

	m_treeSplitter->restoreState(
		settings.value("treeSplitter/State", m_treeSplitter->saveState()).toByteArray());

	connect(m_scriptExplorer, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), 
		this, SLOT(scriptExplorerDoubleClick(QTreeWidgetItem*, int)));

	connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequest(int)));
	connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentTabChange(int)));

	connect(m_scriptExplorer, SIGNAL(enterKeyPressed(QTreeWidgetItem*, int)), this, SLOT(enterKeyPress(QTreeWidgetItem*, int)));
	connect(m_scriptExplorer, SIGNAL(deleteKeyPressed(QTreeWidgetItem*, int)), this, SLOT(deleteKeyPress(QTreeWidgetItem*, int)));
}

void VBlankEditorView::tabCloseRequest(int index)
{
	if (m_tabWidget->count() > 2)
	{
		m_tabManager->removeTab(m_tabWidget->widget(index), VTabManager::Editor);
		m_tabWidget->removeTab(index);
		m_tabWidget->setCurrentIndex(index-1);
	}
	else
	{
		m_tabManager->removeTab(m_tabWidget->widget(0), VTabManager::Editor);
		m_tabManager->removeTab(m_tabWidget->widget(1), VTabManager::View);
		m_tabWidget->removeTab(0);
		m_tabWidget->removeTab(0);
	}
	
	m_curTreeItem = 0;
}

void VBlankEditorView::currentTabChange(int index)
{
	if (m_printerToolbar)
		if (m_tabWidget->currentIndex() == 0)
		{
			m_printerToolbar->setEnabled(false);
			m_formatTbHelper->toolbar()->setEnabled(false);
		}
		else
		{
			m_printerToolbar->setEnabled(true);
			m_formatTbHelper->toolbar()->setEnabled(false);
		}
	
	if (index <= 0)
		return;

	//save script before compile
	actionScriptSave();

	QString scriptText(m_tabManager->editor(m_tabWidget->widget(0))->text());
	
	if (!executeScript(scriptText))
	{
		m_tabWidget->setCurrentIndex(0);		
	}

	m_curTabIdx = index;
}

void VBlankEditorView::enterKeyPress(QTreeWidgetItem* item, int column)
{
	VScriptItem* scriptItem = findCurrentScriptItem();
	openScript(scriptItem->fullFileName());
}

void VBlankEditorView::deleteKeyPress(QTreeWidgetItem* item, int column)
{
	actionScriptDelete();
}

void VBlankEditorView::editorTextChange()
{
	m_tabWidget->setTabText(0, m_tabManager->fileName() + "*");
}

void VBlankEditorView::blankChange()
{
	//m_tabManager->view(m_tabWidget->widget(1))->update(m_blank.get());
	//qDebug() << "blankChange";
}

void VBlankEditorView::blankChange(VAbstractControl* c)
{
	//qDebug() << "blankChange(VAbstractControl* c)" << c->value() << c->typeToString();
}

void VBlankEditorView::actionScriptNew()
{
	QString scriptsDir;
	VSettings settings(QObject::metaObject()->className());	
	scriptsDir = settings.value("scriptsDir", ".").toString();
	
	QString fn = QString(scriptsDir + "/%1%2.qml").arg(DEF_SCRIPT_NAME).arg(m_newScriptCount);
	++m_newScriptCount;

	QFile f(fn);
	if (f.open(QIODevice::ReadWrite))
	{
		f.close();

		VScriptItem* item = new VScriptItem(fn);
		m_scriptItems << item;	
		m_scriptExplorer->expandAll();
		refreshScriptExplorer();

		m_scriptExplorer->setCurrentItem(item->item(), m_scriptExplorer->currentColumn());
		scriptExplorerDoubleClick(item->item(), 0);
	}
}

void VBlankEditorView::actionScriptOpen()
{
	QString scriptsDir;
	VSettings settings(metaObject()->className());

	if (m_lastOpenDir.isEmpty())
		scriptsDir = settings.value("scriptsDir", ".").toString();

	QString fn = QFileDialog::getOpenFileName(this, tr("Open File..."),
		scriptsDir, tr("qml-files (*.qml);;All Files (*)"));
	
	if (!fn.isEmpty())
	{
		if (!QFile::exists(fn))
		{
			showErrors(tr("File %1 not found").arg(fn));
			return;
		}		

		VScriptItem* item = new VScriptItem(fn);
		m_scriptItems << item;
		m_scriptExplorer->expandAll();
		refreshScriptExplorer();

		m_scriptExplorer->setCurrentItem(item->item(), m_scriptExplorer->currentColumn());
		scriptExplorerDoubleClick(item->item(), 0);
	}
}

void VBlankEditorView::actionScriptSave()
{
	VBlankTextEditor* te = m_tabManager->editor(m_tabWidget->widget(0));
	if (!te)
		return;

	VScriptItem* item = findCurrentScriptItem();
	QString fn = m_tabManager->fileNameFull();

	if (fn.isEmpty())
		return;

	QFile f(fn);
	if (f.open(QIODevice::WriteOnly))
	{
		QTextStream s(&f);
		s << te->text();
		f.close();

		m_tabWidget->setTabText(0, m_tabManager->fileName());
	}
	else
		showErrors(tr("Save file '%1' error").arg(fn));

	refreshScriptExplorer();	
}

void VBlankEditorView::actionScriptSaveAs()
{
	VScriptItem* item = findCurrentScriptItem();
	VBlankTextEditor* te = m_tabManager->editor(m_tabWidget->widget(0));
	
	if (!item || !te)
		return;

	QString scriptsDir;
	VSettings settings(metaObject()->className());	
	scriptsDir = settings.value("scriptsDir", ".").toString();

	QString fn = QFileDialog::getSaveFileName(this, tr("Save as..."),
		scriptsDir, tr("qml-files (*.qml);;All Files (*)"));

	if (fn.isEmpty())
		return;
	
	if (!(fn.endsWith(".qml", Qt::CaseInsensitive) ))
		fn += ".qml"; // default

	if (te)
	{
		QFile f(fn);
		if (f.open(QIODevice::WriteOnly))
		{
			QTextStream s(&f);
			QString ss(m_tabManager->editor(m_tabWidget->widget(0))->text());
			ss.replace("\n", "\r\n");
			s << ss;
			f.close();
		}
	}
	else if (item)
	{
		QFile copy(item->fullFileName());
		if (copy.open(QIODevice::ReadOnly))
			copy.copy(fn);
	}
	else
		showErrors(tr("Save file '%1' error").arg(fn));

	// check file existing in list of items
	bool exist = false;
	foreach(VScriptItem* i, m_scriptItems)
		if (i->fullFileName() == fn.toLower())
		{
			exist = true;
			break;
		}

	if (!exist)
	{
		VScriptItem* item = new VScriptItem(fn);
		m_scriptItems << item;
		m_scriptExplorer->topLevelItem(0)->addChild(item->item());
		m_scriptExplorer->setCurrentItem(item->item(), m_scriptExplorer->currentColumn());
		m_scriptExplorer->expandAll();

		refreshScriptExplorer();

		scriptExplorerDoubleClick(item->item(), 0);
	}
}

void VBlankEditorView::actionScriptCopy()
{
	VScriptItem* scriptItem = findCurrentScriptItem();
	if (!scriptItem)
		return;

	QFile f(scriptItem->fullFileName());
	
	if (f.open(QIODevice::ReadOnly))
	{
		QString file(scriptItem->fullFileName());
		QString fileCopy(file.split('.').at(0) + QString("(copy %1).qml").arg(m_copyScriptCount));
		if (f.copy(fileCopy))
		{
			++m_copyScriptCount;

			VScriptItem* item = new VScriptItem(fileCopy);
			m_scriptItems << item;	
			m_scriptExplorer->expandAll();
			refreshScriptExplorer();

			m_scriptExplorer->setCurrentItem(item->item(), m_scriptExplorer->currentColumn());
			scriptExplorerDoubleClick(item->item(), 0);
		}
	}	
}

void VBlankEditorView::actionScriptDelete()
{
	VScriptItem* scriptItem = findCurrentScriptItem();	
	if (scriptItem && QMessageBox::question(0, tr("Delete?"), 
		tr("Delete file %1?").arg(scriptItem->fullFileName()), 
		QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok)
	{
		QDir dir;
		dir.remove(scriptItem->fullFileName());
		
		m_scriptItems.removeOne(scriptItem);
		delete scriptItem;	
	}

	m_curTreeItem = 0;
	refreshScriptExplorer();
}

void VBlankEditorView::scriptExplorerDoubleClick(QTreeWidgetItem* item, int column)
{
	if (m_curTreeItem == item)
		return;

	if (item->text(column) == SRIPT_EXPLORER_TITLE)
		return;

	QString scriptName(item->text(column));	

	if (m_curTreeItem)
		m_curTreeItem->setIcon(column, QIcon());

	m_curTreeItem = item;

	VScriptItem* scriptItem = findCurrentScriptItem();
	if (scriptItem)
	{
		//QString curScriptName(scriptItem->item()->text(column));
		//curScriptName += CUR_SCRIPT_MARKER;
		item->setText(column, scriptItem->item()->text(column));
		item->setIcon(column, QIcon(CUR_SCRIPT_ICON));

		openScript(scriptItem->fullFileName());	
	}
}

void VBlankEditorView::appendExistScripts()
{
	QString scriptsDir;

	VSettings settings(metaObject()->className());
	scriptsDir = settings.value("scriptsDir", ".").toString();

	QDir curDir(scriptsDir);
	QStringList filters;
	filters << "*.qml";
	curDir.setNameFilters(filters);

	foreach (QString fileName, curDir.entryList(QDir::Files))
	{
		VScriptItem* item = new VScriptItem(qApp->applicationDirPath() + "/" + scriptsDir + "/" + fileName);
		m_scriptItems << item;
		m_scriptExplorer->topLevelItem(0)->addChild(item->item());
		m_scriptExplorer->expandAll();
	}
}

void VBlankEditorView::openScript(const QString& scriptFullName)
{
	/*int idx = -1;
	
	QWidget* w = m_tabManager->findTab(scriptFullName.toLower());

	if (!w)
	{
		QWidget* tab = m_tabManager->addTab(m_tabWidget, scriptFullName, VTabManager::Editor);
		
		if (m_tabWidget->count() > 1)
		{
			m_tabWidget->removeTab(m_tabWidget->count()-1); // remove blank view tab		
			idx = m_tabWidget->addTab(tab, scriptFullName.section('/', -1));
			QWidget* bvTab = m_tabManager->findTab(scriptFullName, VTabManager::View);
			m_tabWidget->addTab(bvTab, scriptFullName.section('/', -1), false);
		}
		else
			idx = m_tabWidget->addTab(tab, scriptFullName.section('/', -1));

		QFile file(scriptFullName);
		if (!file.open(QFile::ReadOnly))
		{
			showErrors(tr("Open file %1 error").arg(scriptFullName));
			return;
		}

		QTextStream s(&file);
		QString scriptText(s.readAll());

		m_tabManager->editor(tab)->setText(scriptText);
	}
	else
	{
		for (int i=0; i<m_tabWidget->count(); ++i)
		{
			if (w == m_tabWidget->widget(i))
			{
				idx = i;
				break;
			}
		}
	}

	if (m_tabManager->count(VTabManager::Editor) == 1)
	{
		QWidget* tab = m_tabManager->addTab(m_tabWidget, scriptFullName, VTabManager::View);
		m_tabWidget->addTab(tab, scriptFullName.section('/', -1), false);
	}
	
	m_tabWidget->setCurrentIndex(idx);*/

	QFile file(scriptFullName);
	if (!file.open(QFile::ReadOnly))
	{
		showErrors(tr("Open file %1 error").arg(scriptFullName));
		return;
	}

	QTextStream s(&file);
	QString scriptText(s.readAll());
	
	//m_tabWidget->removeTab(0);
	//m_tabWidget->removeTab(0);

	if (m_tabManager->count(VTabManager::Editor) == 0)
	{
		QWidget* tab = m_tabManager->addTab(m_tabWidget, scriptFullName, VTabManager::Editor);
		tab->layout()->setMargin(0);
		m_tabWidget->addTab(tab, scriptFullName.section('/', -1));

		VSettings settings(metaObject()->className());
		QString fontFamily = settings.value("fontFamily", "Courier New").toString();
		int fontPointSize = settings.value("fontPointSize", "12").toInt();
		int tabSize = settings.value("tabSize", "2").toInt();
		
		QFont font;
		font.setFamily(fontFamily);
		font.setPointSize(fontPointSize);
		m_tabManager->editor(tab)->setFont(font);
		//m_tabManager->editor(tab)->setWordWrapMode(QTextOption::NoWrap);
		m_tabManager->editor(tab)->setTabWidth(tabSize);

		connect(m_tabManager->editor(tab), SIGNAL(textChanged()), this, SLOT(editorTextChange()));	

		m_tabManager->editor(tab)->setText(scriptText);
		
		tab = m_tabManager->addTab(m_tabWidget, scriptFullName, VTabManager::View);
		//tab->layout()->setMargin(0);
		m_tabWidget->addTab(tab, scriptFullName.section('/', -1), false);
	}

	m_tabWidget->setCurrentIndex(0);
	m_tabManager->setFileNameFull(scriptFullName);
	qDebug() << scriptFullName << m_tabManager->fileName();
	m_tabWidget->setTabText(0, m_tabManager->fileName());
	m_tabManager->editor(m_tabWidget->widget(0))->setText(scriptText);
}

bool VBlankEditorView::executeScript(const QString& script)
{
	if (!m_compiler)
	{
		m_compiler.reset(new VQMLCompiler);
		connect(m_compiler.get(), SIGNAL(warnings(const QList<QDeclarativeError>&)), this, SLOT(showWarnings(const QList<QDeclarativeError>&)));
	}

	m_log->clear();

	QUrl url;
	
	//if (m_blank)
	//	QObject::disconnect(this, SIGNAL(blankChanged()));
	
	m_blank.reset(m_compiler->execute(script, QUrl(m_tabManager->fileName())));
	if (!m_blank)
	{
		showErrors(tr("File '%1' compile error").arg(m_tabManager->fileNameFull()));
		showErrors(m_compiler->errors());
		return false;
	}

	connect(m_blank.get(), SIGNAL(blankChanged()), this, SLOT(blankChange()));
	connect(m_blank.get(), SIGNAL(blankChanged(VAbstractControl*)), this, SLOT(blankChange(VAbstractControl*)));
	m_tabManager->view(m_tabWidget->widget(1))->update(m_blank.get());

	QList<VAbstractControl*> controls(m_blank->controlWithFocusList());
	foreach(VAbstractControl* c, controls)
		if (c->type() == VAbstractControl::TextEdit)
		{
			VTextEdit* te = qobject_cast<VTextEdit*>(c);
			connect(te, SIGNAL(signalControlGotFocus(VAbstractControl*)), m_formatTbHelper, SLOT(slotControlGotFocus(VAbstractControl*)));
			connect(te, SIGNAL(signalControlLostFocus(VAbstractControl*)), m_formatTbHelper, SLOT(slotControlLostFocus(VAbstractControl*)));
		}
		else if (c->type() == VAbstractControl::LineEdit)
		{
			VLineEdit* le = qobject_cast<VLineEdit*>(c);
			connect(le, SIGNAL(signalControlGotFocus(VAbstractControl*)), m_formatTbHelper, SLOT(slotControlGotFocus(VAbstractControl*)));
		}


	return true;
}

void VBlankEditorView::showErrors(const QString& errors) const
{
	qxtLog->error(errors + "\r");
	m_log->append(errors);	
}

void VBlankEditorView::showErrors(const QList<QDeclarativeError>& errors) const
{
	foreach(QDeclarativeError e, errors)
		showErrors(e.toString());

	QDeclarativeError ee(errors[0]);
	QPoint errPos( ee.column()-1, ee.line()-5);
	VBlankTextEditor* editor = m_tabManager->editor();
	if (editor)
		editor->setCursorPos(errPos.y(), errPos.x());
}

void VBlankEditorView::showWarnings(const QList<QDeclarativeError>& w)
{
	foreach(QDeclarativeError e, w)
		showErrors(e.toString());
}

void VBlankEditorView::refreshScriptExplorer()
{
	foreach(VScriptItem* i, m_scriptItems)
		m_scriptExplorer->topLevelItem(0)->addChild(i->item());
	
	m_scriptExplorer->expandAll();
}

VScriptItem* VBlankEditorView::findCurrentScriptItem() const
{
	QTreeWidgetItem* curItem = m_scriptExplorer->currentItem();

	foreach(VScriptItem* i, m_scriptItems)
		if (i->item() == curItem)
			return i;

	return 0;
}

void VBlankEditorView::filePrint()
{
	QPrinter printer;//(QPrinter::HighResolution);
	QPrintDialog *dlg = new QPrintDialog(&printer, this);
	//if (textEdit->textCursor().hasSelection())
	//	dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
	dlg->setWindowTitle(tr("Print Document"));
	if (dlg->exec() == QDialog::Accepted) {
		//textEdit->print(&printer);
		/*QPainter painter(&printer);
		QRect rect = painter.viewport();
		QPixmap image(blankViewToPixmap());
		QSize size = image.size();
		//size.scale(rect.size(), Qt::KeepAspectRatio);
		painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
		painter.setWindow(image.rect());
		painter.drawPixmap(QPoint(), image);*/
		/*QWidget* w(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
		QPainter painter(&printer);
		QRect rect = painter.viewport();
		QSize size = w->size();
		size.scale(rect.size(), Qt::KeepAspectRatio);
		qDebug() << rect.x() << rect.y() << size.width() << size.height();
		painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
		painter.setWindow(w->rect());
		w->render(&painter);*/

		QPrinter printer(QPrinter::HighResolution);
		printer.setPaperSize(QPrinter::A4);

		QPainter painter(&printer);
		m_graphScene->addWidget(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
		m_graphScene->render(&painter);
	}
	delete dlg;
}

void VBlankEditorView::filePrintPreview()
{
	QPrinter printer;//(QPrinter::HighResolution);
	QPrintPreviewDialog preview(&printer, this);
	connect(&preview, SIGNAL(paintRequested(QPrinter*)), SLOT(printPreview(QPrinter*)));
	preview.exec();
}

void VBlankEditorView::printPreview(QPrinter *printer)
{
	/*QPainter painter(printer);
	QRect rect = painter.viewport();
	QPixmap image(blankViewToPixmap());
	QSize size = image.size();
	size.scale(rect.size(), Qt::KeepAspectRatio);
	qDebug() << rect.x() << rect.y() << size.width() << size.height();
	painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
	painter.setWindow(image.rect());
	//painter.drawImage(0, 0, image);
	painter.drawPixmap(QPoint(), image);*/
	
	/*QPainter painter;
	painter.begin(printer);
	QPixmap p(blankViewToPixmap());
	painter.drawPixmap(QPoint(), p, QRect(0, 0, p.width(), p.height()));    
	painter.end();*/
	//p.toImage().save( "c:\\out2.png", "PNG" );

	/*QWidget* w(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
	w->render(printer);

	QPixmap pixmap(w->size());
	w->render(&pixmap);*/

	/*QWidget* w(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
	QPainter painter(printer);
	QRect rect = painter.viewport();
	QSize size = w->size();
	size.scale(rect.size(), Qt::KeepAspectRatio);
	qDebug() << rect.x() << rect.y() << size.width() << size.height();
	painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
	painter.setWindow(w->rect());
	w->render(&painter);*/

	m_proxyWidget = new QGraphicsProxyWidget;
	QWidget* w(m_tabManager->view(m_tabWidget->widget(1))->widget());
	//w->setParent(0); 
	m_proxyWidget->setWidget(w);
	//m_proxyWidget = m_graphScene->addWidget(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
	m_graphScene->addWidget(m_tabManager->view(m_tabWidget->widget(1))->printWidget());
	printer->setPaperSize(QPrinter::A4);
	QPainter painter(printer);
	m_graphScene->render(&painter);
}

QPixmap VBlankEditorView::blankViewToPixmap() const
{
	//QWidget* w(m_tabWidget->widget(1));
	QWidget* w(m_tabManager->view(m_tabWidget->widget(1))->printWidget());	
	QPixmap p(QPixmap::grabWidget(w));
	//p.load("c:\\med_gallery_78561_4912_25193.jpg");
	qDebug() << w->geometry() << p.size();
	return p;
}
